home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / Managed / Direct3D / SimpleAnimation / SimpleAnimation.cs < prev    next >
Encoding:
Text File  |  2004-09-27  |  36.9 KB  |  847 lines

  1. //-----------------------------------------------------------------------------
  2. // File: SimpleAnimation.cs
  3. //
  4. // Simple skeletal animation using Managed DirectX
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8.  
  9.  
  10. //#define DEBUG_VS   // Uncomment this line to debug vertex shaders 
  11. //#define DEBUG_PS   // Uncomment this line to debug pixel shaders 
  12.  
  13. using System;
  14. using Microsoft.DirectX;
  15. using Microsoft.DirectX.Direct3D;
  16. using Microsoft.Samples.DirectX.UtilityToolkit;
  17.  
  18. namespace SimpleAnimationSample
  19. {
  20.     /// <summary>SimpleAnimation Sample Class</summary>
  21.     public class SimpleAnimation : IFrameworkCallback, IDeviceCreation
  22.     {
  23.         #region Creation
  24.         /// <summary>Create a new instance of the class</summary>
  25.         public SimpleAnimation(Framework f) 
  26.         { 
  27.             // Store framework
  28.             sampleFramework = f; 
  29.             // Create dialogs
  30.             hud = new Dialog(sampleFramework); 
  31.         }
  32.         #endregion
  33.  
  34.         // Variables
  35.         private Framework sampleFramework = null; // Framework for samples
  36.         private Font statsFont = null; // Font for drawing text
  37.         private Sprite textSprite = null; // Sprite for batching text calls
  38.         private Effect effect = null; // D3DX Effect Interface
  39.         private ModelViewerCamera camera = new ModelViewerCamera(); // A model viewing camera
  40.         private bool isHelpShowing = false; // If true, renders the UI help text
  41.         private Dialog hud = null; // dialog for standard controls
  42.  
  43.         // Sample specific items
  44.  
  45.         // Animation root frame
  46.         private AnimationRootFrame rootFrame; 
  47.         private float objectRadius = 0.0f; // Radius of the object
  48.         private Vector3 objectCenter; // Center of the object
  49.         private static readonly ColorValue WhiteColor = new ColorValue(1.0f, 1.0f, 1.0f, 1.0f);
  50.         private static readonly ColorValue Color2 = new ColorValue(0.25f, 0.25f, 0.25f, 1.0f);
  51.  
  52.         // HUD Ui Control constants
  53.         private const int ToggleFullscreen = 1;
  54.         private const int ToggleReference = 3;
  55.         private const int ChangeDevice = 4;
  56.  
  57.         /// <summary>
  58.         /// Called during device initialization, this code checks the device for some 
  59.         /// minimum set of capabilities, and rejects those that don't pass by returning false.
  60.         /// </summary>
  61.         public bool IsDeviceAcceptable(Caps caps, Format adapterFormat, Format backBufferFormat, bool windowed)
  62.         {
  63.             // Skip back buffer formats that don't support alpha blending
  64.             if (!Manager.CheckDeviceFormat(caps.AdapterOrdinal, caps.DeviceType, adapterFormat, 
  65.                 Usage.QueryPostPixelShaderBlending, ResourceType.Textures, backBufferFormat))
  66.                 return false;
  67.  
  68.             // Need blend indices
  69.             if (caps.MaxVertexBlendMatrixIndex < 12)
  70.                 return false;
  71.  
  72.             return true;
  73.         }
  74.  
  75.         /// <summary>
  76.         /// This callback function is called immediately before a device is created to allow the 
  77.         /// application to modify the device settings. The supplied settings parameter 
  78.         /// contains the settings that the framework has selected for the new device, and the 
  79.         /// application can make any desired changes directly to this structure.  Note however that 
  80.         /// the sample framework will not correct invalid device settings so care must be taken 
  81.         /// to return valid device settings, otherwise creating the Device will fail.  
  82.         /// </summary>
  83.         public void ModifyDeviceSettings(DeviceSettings settings, Caps caps)
  84.         {
  85.             // If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW 
  86.             // then switch to SWVP.
  87.             if ( (!caps.DeviceCaps.SupportsHardwareTransformAndLight) ||
  88.                 (caps.VertexShaderVersion < new Version(1,1)) )
  89.             {
  90.                 settings.BehaviorFlags = CreateFlags.SoftwareVertexProcessing;
  91.             }
  92.             else
  93.             {
  94.                 settings.BehaviorFlags = CreateFlags.HardwareVertexProcessing;
  95.             }
  96.  
  97.             // This application is designed to work on a pure device by not using 
  98.             // any get methods, so create a pure device if supported and using HWVP.
  99.             if ( (caps.DeviceCaps.SupportsPureDevice) && 
  100.                 ((settings.BehaviorFlags & CreateFlags.HardwareVertexProcessing) != 0 ) )
  101.                 settings.BehaviorFlags |= CreateFlags.PureDevice;
  102.  
  103.             // Debugging vertex shaders requires either REF or software vertex processing 
  104.             // and debugging pixel shaders requires REF.  
  105. #if(DEBUG_VS)
  106.             if (settings.DeviceType != DeviceType.Reference )
  107.             {
  108.                 settings.BehaviorFlags &= ~CreateFlags.HardwareVertexProcessing;
  109.                 settings.BehaviorFlags |= CreateFlags.SoftwareVertexProcessing;
  110.             }
  111. #endif
  112. #if(DEBUG_PS)
  113.             settings.DeviceType = DeviceType.Reference;
  114. #endif
  115.  
  116.         }
  117.  
  118.         /// <summary>
  119.         /// This event will be fired immediately after the Direct3D device has been 
  120.         /// created, which will happen during application initialization and windowed/full screen 
  121.         /// toggles. This is the best location to create Pool.Managed resources since these 
  122.         /// resources need to be reloaded whenever the device is destroyed. Resources created  
  123.         /// here should be released in the Disposing event. 
  124.         /// </summary>
  125.         private void OnCreateDevice(object sender, DeviceEventArgs e)
  126.         {
  127.             // Initialize the stats font
  128.             statsFont = ResourceCache.GetGlobalInstance().CreateFont(e.Device, 15, 0, FontWeight.Bold, 1, false, CharacterSet.Default,
  129.                 Precision.Default, FontQuality.Default, PitchAndFamily.FamilyDoNotCare | PitchAndFamily.DefaultPitch
  130.                 , "Arial");
  131.  
  132.             // Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the 
  133.             // shader debugger. Debugging vertex shaders requires either REF or software vertex 
  134.             // processing, and debugging pixel shaders requires REF.  The 
  135.             // ShaderFlags.Force*SoftwareNoOptimizations flag improves the debug experience in the 
  136.             // shader debugger.  It enables source level debugging, prevents instruction 
  137.             // reordering, prevents dead code elimination, and forces the compiler to compile 
  138.             // against the next higher available software target, which ensures that the 
  139.             // unoptimized shaders do not exceed the shader model limitations.  Setting these 
  140.             // flags will cause slower rendering since the shaders will be unoptimized and 
  141.             // forced into software.  See the DirectX documentation for more information about 
  142.             // using the shader debugger.
  143.             ShaderFlags shaderFlags = ShaderFlags.None;
  144. #if(DEBUG_VS)
  145.             shaderFlags |= ShaderFlags.ForceVertexShaderSoftwareNoOptimizations;
  146. #endif
  147. #if(DEBUG_PS)
  148.             shaderFlags |= ShaderFlags.ForcePixelShaderSoftwareNoOptimizations;
  149. #endif
  150.             // Read the D3DX effect file
  151.             string path = Utility.FindMediaFile("SimpleAnimation.fx");
  152.             effect = ResourceCache.GetGlobalInstance().CreateEffectFromFile(e.Device,
  153.                 path, null, null, shaderFlags, null);
  154.  
  155.             // Create our allocate hierarchy derived class
  156.             AnimationAllocation alloc = new AnimationAllocation(this);
  157.  
  158.             // Load our file
  159.             string meshFile = Utility.FindMediaFile("tiny\\tiny.x");
  160.             // Store the current folder, then switch to the folder where the media was found
  161.             string currentFolder = System.IO.Directory.GetCurrentDirectory();
  162.             System.IO.Directory.SetCurrentDirectory(new System.IO.FileInfo(meshFile).Directory.FullName);
  163.             // Now load the mesh hierarchy
  164.             rootFrame = Mesh.LoadHierarchyFromFile(meshFile, MeshFlags.Managed, e.Device, alloc, null);
  165.             // Restore the folder
  166.             System.IO.Directory.SetCurrentDirectory(currentFolder);
  167.  
  168.             // Calculate the center and radius of a bounding sphere
  169.             objectRadius = Frame.CalculateBoundingSphere(rootFrame.FrameHierarchy, 
  170.                 out objectCenter);
  171.  
  172.             // Setup the matrices for animation
  173.             SetupBoneMatrices(rootFrame.FrameHierarchy as AnimationFrame);
  174.         }
  175.         
  176.         /// <summary>
  177.         /// This event will be fired immediately after the Direct3D device has been 
  178.         /// reset, which will happen after a lost device scenario. This is the best location to 
  179.         /// create Pool.Default resources since these resources need to be reloaded whenever 
  180.         /// the device is lost. Resources created here should be released in the OnLostDevice 
  181.         /// event. 
  182.         /// </summary>
  183.         private void OnResetDevice(object sender, DeviceEventArgs e)
  184.         {
  185.             SurfaceDescription desc = e.BackBufferDescription;
  186.             // Create a sprite to help batch calls when drawing many lines of text
  187.             textSprite = new Sprite(e.Device);
  188.  
  189.             // Setup the camera's projection parameters
  190.             float aspectRatio = (float)desc.Width / (float)desc.Height;
  191.             camera.SetProjectionParameters((float)Math.PI / 4, aspectRatio, objectRadius / 64.0f, objectRadius * 200.0f);
  192.             camera.SetViewParameters(new Vector3(0, 0, -2.2f * objectRadius), Vector3.Empty);
  193.             camera.SetWindow(desc.Width, desc.Height);
  194.  
  195.             // Set device transforms
  196.             e.Device.Transform.Projection = camera.ProjectionMatrix;
  197.             e.Device.Transform.View = camera.ViewMatrix;
  198.  
  199.             // Setup a light
  200.             e.Device.Lights[0].Type = LightType.Directional;
  201.             e.Device.Lights[0].Direction = new Vector3(0.0f, -1.0f, 1.0f);
  202.             e.Device.Lights[0].DiffuseColor = WhiteColor;
  203.             e.Device.Lights[0].Enabled = true;
  204.  
  205.             // Setup UI locations
  206.             hud.SetLocation(desc.Width-170, 0);
  207.             hud.SetSize(170,170);
  208.         }
  209.  
  210.         /// <summary>
  211.         /// This event function will be called fired after the Direct3D device has 
  212.         /// entered a lost state and before Device.Reset() is called. Resources created
  213.         /// in the OnResetDevice callback should be released here, which generally includes all 
  214.         /// Pool.Default resources. See the "Lost Devices" section of the documentation for 
  215.         /// information about lost devices.
  216.         /// </summary>
  217.         private void OnLostDevice(object sender, EventArgs e)
  218.         {
  219.             if (textSprite != null)
  220.             {
  221.                 textSprite.Dispose();
  222.                 textSprite = null;
  223.             }
  224.         }
  225.  
  226.         /// <summary>
  227.         /// This callback function will be called immediately after the Direct3D device has 
  228.         /// been destroyed, which generally happens as a result of application termination or 
  229.         /// windowed/full screen toggles. Resources created in the OnCreateDevice callback 
  230.         /// should be released here, which generally includes all Pool.Managed resources. 
  231.         /// </summary>
  232.         private void OnDestroyDevice(object sender, EventArgs e)
  233.         {
  234.             Frame.Destroy(rootFrame.FrameHierarchy, new AnimationAllocation(this));
  235.             if (rootFrame.AnimationController != null)
  236.             {
  237.                 rootFrame.AnimationController.Dispose();
  238.             }
  239.         }
  240.  
  241.         /// <summary>
  242.         /// This callback function will be called once at the beginning of every frame. This is the
  243.         /// best location for your application to handle updates to the scene, but is not 
  244.         /// intended to contain actual rendering calls, which should instead be placed in the 
  245.         /// OnFrameRender callback.  
  246.         /// </summary>
  247.         public void OnFrameMove(Device device, double appTime, float elapsedTime)
  248.         {
  249.             // Update the camera's position based on user input 
  250.             camera.FrameMove(elapsedTime);
  251.  
  252.             // Build the world matrix
  253.             Matrix worldMatrix = Matrix.Translation(-objectCenter);
  254.             worldMatrix *= camera.WorldMatrix;
  255.  
  256.             // Set world matrix
  257.             device.Transform.World = worldMatrix;
  258.  
  259.             // Has any time elapsed?
  260.             if (elapsedTime > 0.0f)
  261.             {
  262.                 if (rootFrame.AnimationController != null)
  263.                     rootFrame.AnimationController.AdvanceTime(elapsedTime);
  264.  
  265.                 UpdateFrameMatrices(rootFrame.FrameHierarchy as AnimationFrame,
  266.                     worldMatrix);
  267.             }
  268.         }
  269.  
  270.         /// <summary>
  271.         /// This callback function will be called at the end of every frame to perform all the 
  272.         /// rendering calls for the scene, and it will also be called if the window needs to be 
  273.         /// repainted. After this function has returned, the sample framework will call 
  274.         /// Device.Present to display the contents of the next buffer in the swap chain
  275.         /// </summary>
  276.         public void OnFrameRender(Device device, double appTime, float elapsedTime)
  277.         {
  278.             bool beginSceneCalled = false;
  279.  
  280.             // Clear the render target and the zbuffer 
  281.             device.Clear(ClearFlags.ZBuffer | ClearFlags.Target, 0x002D32AA, 1.0f, 0);
  282.             try
  283.             {
  284.                 device.BeginScene();
  285.                 beginSceneCalled = true;
  286.  
  287.                 // Update the effect's variables.  Instead of using strings, it would 
  288.                 // be more efficient to cache a handle to the parameter by calling 
  289.                 // Effect.GetParameter
  290.                 effect.SetValue("mViewProj", camera.ProjectionMatrix);
  291.                 Vector4 lightDir = new Vector4(0.0f, 1.0f, -1.0f, 0.0f);
  292.                 lightDir.Normalize();
  293.                 effect.SetValue("lhtDir", lightDir);
  294.  
  295.                 // Render the animation
  296.                 DrawFrame(rootFrame.FrameHierarchy as AnimationFrame);
  297.  
  298.                 // Show frame rate
  299.                 RenderText();
  300.  
  301.                 // Show UI
  302.                 hud.OnRender(elapsedTime);
  303.             }
  304.             finally
  305.             {
  306.                 if (beginSceneCalled)
  307.                     device.EndScene();
  308.             }
  309.         }
  310.         /// <summary>Update the frames matrices and combine it with it's parents</summary>
  311.         private void UpdateFrameMatrices(AnimationFrame frame, Matrix parentMatrix)
  312.         {
  313.             frame.CombinedTransformationMatrix = frame.TransformationMatrix * 
  314.                 parentMatrix;
  315.  
  316.             if (frame.FrameSibling != null)
  317.             {
  318.                 UpdateFrameMatrices(frame.FrameSibling as AnimationFrame, parentMatrix);
  319.             }
  320.  
  321.             if (frame.FrameFirstChild != null)
  322.             {
  323.                 UpdateFrameMatrices(frame.FrameFirstChild as AnimationFrame, 
  324.                     frame.CombinedTransformationMatrix);
  325.             }
  326.         }
  327.  
  328.         /// <summary>Draw a frame and all child and sibling frames</summary>
  329.         private void DrawFrame(AnimationFrame frame)
  330.         {
  331.             AnimationMeshContainer mesh = frame.MeshContainer as AnimationMeshContainer;
  332.             while(mesh != null)
  333.             {
  334.                 DrawMeshContainer(mesh, frame);
  335.  
  336.                 mesh = mesh.NextContainer as AnimationMeshContainer;
  337.             }
  338.  
  339.             if (frame.FrameSibling != null)
  340.             {
  341.                 DrawFrame(frame.FrameSibling as AnimationFrame);
  342.             }
  343.  
  344.             if (frame.FrameFirstChild != null)
  345.             {
  346.                 DrawFrame(frame.FrameFirstChild as AnimationFrame);
  347.             }
  348.         }
  349.  
  350.         /// <summary>Render a mesh container</summary>
  351.         private void DrawMeshContainer(AnimationMeshContainer mesh, AnimationFrame parent)
  352.         {
  353.             Device device = sampleFramework.Device;
  354.             // first check for skinning
  355.             if (mesh.SkinInformation != null)
  356.             {
  357.                 if (mesh.NumberInfluences == 1)
  358.                     device.RenderState.VertexBlend = VertexBlend.ZeroWeights;
  359.                 else
  360.                     device.RenderState.VertexBlend = (VertexBlend)(mesh.NumberInfluences - 1);
  361.  
  362.                 if (mesh.NumberInfluences > 0)
  363.                     device.RenderState.IndexedVertexBlendEnable = true;
  364.  
  365.                 BoneCombination[] bones = mesh.GetBones();
  366.  
  367.                 for(int iAttrib = 0; iAttrib < mesh.NumberAttributes; iAttrib++)
  368.                 {
  369.                     // first, get world matrices
  370.                     for (int iPaletteEntry = 0; iPaletteEntry < mesh.NumberPaletteEntries; 
  371.                         ++iPaletteEntry)
  372.                     {
  373.                         int iMatrixIndex = bones[iAttrib].BoneId[iPaletteEntry];
  374.                         if (iMatrixIndex != -1)
  375.                         {
  376.                             device.Transform.SetWorldMatrixByIndex(iPaletteEntry, 
  377.                                 mesh.GetOffsetMatrices()[iMatrixIndex] * 
  378.                                 mesh.GetFrames()[iMatrixIndex].
  379.                                 CombinedTransformationMatrix);
  380.  
  381.                         }
  382.                     }
  383.  
  384.                     // Setup the material
  385.                     device.Material = mesh.GetMaterials()[bones[iAttrib].AttributeId].Material3D;
  386.                     device.SetTexture(0, mesh.GetTextures()[bones[iAttrib].AttributeId]);
  387.  
  388.                     // Finally draw the subset
  389.                     mesh.MeshData.Mesh.DrawSubset(iAttrib);
  390.                 }
  391.             }
  392.             else
  393.             {
  394.                 // Standard mesh, just draw it using FF
  395.  
  396.                 // Set up transforms
  397.                 device.Transform.World = parent.CombinedTransformationMatrix;
  398.  
  399.                 ExtendedMaterial[] materials = mesh.GetMaterials();
  400.                 for (int i = 0; i < materials.Length; ++i)
  401.                 {
  402.                     device.Material = materials[i].Material3D;
  403.                     device.SetTexture(0, mesh.GetTextures()[i]);
  404.                     mesh.MeshData.Mesh.DrawSubset(i);
  405.                 }
  406.             }
  407.         }
  408.  
  409.  
  410.         /// <summary>
  411.         /// Render the help and statistics text. This function uses the Font object for 
  412.         /// efficient text rendering.
  413.         /// </summary>
  414.         private void RenderText()
  415.         {
  416.             TextHelper txtHelper = new TextHelper(statsFont, textSprite, 15);
  417.  
  418.             // Output statistics
  419.             txtHelper.Begin();
  420.             txtHelper.SetInsertionPoint(5,5);
  421.             txtHelper.SetForegroundColor(System.Drawing.Color.Yellow);
  422.             txtHelper.DrawTextLine(sampleFramework.FrameStats);
  423.             txtHelper.DrawTextLine(sampleFramework.DeviceStats);
  424.  
  425.             txtHelper.SetForegroundColor(System.Drawing.Color.White);
  426.             txtHelper.DrawTextLine("Rendering simple animation");
  427.  
  428.             // Draw help
  429.             if (isHelpShowing)
  430.             {
  431.                 txtHelper.SetInsertionPoint(10, sampleFramework.BackBufferSurfaceDescription.Height-15*6);
  432.                 txtHelper.SetForegroundColor(System.Drawing.Color.DarkOrange);
  433.                 txtHelper.DrawTextLine("Controls (F1 to hide):");
  434.  
  435.                 txtHelper.SetInsertionPoint(40, sampleFramework.BackBufferSurfaceDescription.Height-15*5);
  436.                 txtHelper.DrawTextLine("Quit: Esc");
  437.                 txtHelper.DrawTextLine("Hide help: F1");
  438.             }
  439.             else
  440.             {
  441.                 txtHelper.SetInsertionPoint(10, sampleFramework.BackBufferSurfaceDescription.Height-15*2);
  442.                 txtHelper.SetForegroundColor(System.Drawing.Color.White);
  443.                 txtHelper.DrawTextLine("Press F1 for help");
  444.             }
  445.  
  446.             txtHelper.End();
  447.         }
  448.  
  449.         /// <summary>
  450.         /// As a convenience, the sample framework inspects the incoming windows messages for
  451.         /// keystroke messages and decodes the message parameters to pass relevant keyboard
  452.         /// messages to the application.  The framework does not remove the underlying keystroke 
  453.         /// messages, which are still passed to the application's MsgProc callback.
  454.         /// </summary>
  455.         private void OnKeyEvent(System.Windows.Forms.Keys key, bool isKeyDown, bool isKeyUp)
  456.         {
  457.             if (isKeyDown)
  458.             {
  459.                 switch(key)
  460.                 {
  461.                     case System.Windows.Forms.Keys.F1:
  462.                         isHelpShowing = !isHelpShowing;
  463.                         break;
  464.                 }
  465.             }
  466.         }
  467.  
  468.         /// <summary>
  469.         /// Before handling window messages, the sample framework passes incoming windows 
  470.         /// messages to the application through this callback function. If the application sets 
  471.         /// noFurtherProcessing to true, the sample framework will not process the message
  472.         /// </summary>
  473.         public IntPtr OnMsgProc(IntPtr hWnd, NativeMethods.WindowMessage msg, IntPtr wParam, IntPtr lParam, ref bool noFurtherProcessing)
  474.         {
  475.             // Give the dialog a chance to handle the message first
  476.             noFurtherProcessing = hud.MessageProc(hWnd, msg, wParam, lParam);
  477.             if (noFurtherProcessing)
  478.                 return IntPtr.Zero;
  479.  
  480.             // Pass all remaining windows messages to camera so it can respond to user input
  481.             camera.HandleMessages(hWnd, msg, wParam, lParam);
  482.  
  483.             return IntPtr.Zero;
  484.         }
  485.  
  486.         /// <summary>
  487.         /// Generate the skinned mesh information
  488.         /// </summary>
  489.         public void GenerateSkinnedMesh(AnimationMeshContainer mesh)
  490.         {
  491.             if (mesh.SkinInformation == null)
  492.                 throw new ArgumentException();  // There is nothing to generate
  493.  
  494.             MeshFlags flags = MeshFlags.OptimizeVertexCache;
  495.  
  496.             Caps caps = sampleFramework.DeviceCaps;
  497.             if (caps.VertexShaderVersion >= new Version(1,1))
  498.             {
  499.                 flags |= MeshFlags.Managed;
  500.             }
  501.             else
  502.             {
  503.                 flags |= MeshFlags.SystemMemory;
  504.             }
  505.  
  506.             int numMaxFaceInfl;
  507.             using(IndexBuffer ib = mesh.MeshData.Mesh.IndexBuffer)
  508.             {
  509.                 numMaxFaceInfl = mesh.SkinInformation.GetMaxFaceInfluences(ib, 
  510.                     mesh.MeshData.Mesh.NumberFaces);
  511.             }
  512.             // 12 entry palette guarantees that any triangle (4 independent 
  513.             // influences per vertex of a tri) can be handled
  514.             numMaxFaceInfl = (int)Math.Min(numMaxFaceInfl, 12);
  515.  
  516.             if (caps.MaxVertexBlendMatrixIndex + 1 >= numMaxFaceInfl)
  517.             {
  518.                 mesh.NumberPaletteEntries = (int)Math.Min((caps.
  519.                     MaxVertexBlendMatrixIndex+ 1) / 2, 
  520.                     mesh.SkinInformation.NumberBones);
  521.  
  522.                 flags |= MeshFlags.Managed;
  523.             }
  524.  
  525.             int influences = 0;
  526.             BoneCombination[] bones = null;
  527.  
  528.             // Use ConvertToBlendedMesh to generate a drawable mesh
  529.             MeshData data = mesh.MeshData;
  530.             data.Mesh = mesh.SkinInformation.ConvertToIndexedBlendedMesh(data.Mesh, flags, 
  531.                 mesh.GetAdjacencyStream(), mesh.NumberPaletteEntries, out influences, 
  532.                 out bones);
  533.  
  534.             // Store this info
  535.             mesh.NumberInfluences = influences;
  536.             mesh.SetBones(bones);
  537.  
  538.             // Get the number of attributes
  539.             mesh.NumberAttributes = bones.Length;
  540.  
  541.             mesh.MeshData = data;
  542.         }
  543.  
  544.         /// <summary>This method will set the bone matrices for a frame</summary>
  545.         private void SetupBoneMatrices(AnimationFrame frame)
  546.         {
  547.             // First do the mesh container this frame contains (if it does)
  548.             if (frame.MeshContainer != null)
  549.             {
  550.                 SetupBoneMatrices(frame.MeshContainer as AnimationMeshContainer);
  551.             }
  552.             // Next do any siblings this frame may contain
  553.             if (frame.FrameSibling != null)
  554.             {
  555.                 SetupBoneMatrices(frame.FrameSibling as AnimationFrame);
  556.             }
  557.             // Finally do the children of this frame
  558.             if (frame.FrameFirstChild != null)
  559.             {
  560.                 SetupBoneMatrices(frame.FrameFirstChild as AnimationFrame);
  561.             }
  562.         }
  563.  
  564.         /// <summary>Sets the bone matrices for a mesh container</summary>
  565.         private void SetupBoneMatrices(AnimationMeshContainer mesh)
  566.         {
  567.             // Is there skin information?  If so, setup the matrices
  568.             if (mesh.SkinInformation != null)
  569.             {
  570.                 int numberBones = mesh.SkinInformation.NumberBones;
  571.  
  572.                 AnimationFrame[] frameMatrices = new AnimationFrame[numberBones];
  573.                 for(int i = 0; i< numberBones; i++)
  574.                 {
  575.                     AnimationFrame frame = Frame.Find(rootFrame.FrameHierarchy, 
  576.                         mesh.SkinInformation.GetBoneName(i)) as AnimationFrame;
  577.  
  578.                     if (frame == null)
  579.                         throw new InvalidOperationException("Could not find valid bone.");
  580.  
  581.                     frameMatrices[i] = frame;
  582.                 }
  583.                 mesh.SetFrames(frameMatrices);
  584.             }
  585.         }
  586.  
  587.  
  588.         /// <summary>
  589.         /// Initializes the application
  590.         /// </summary>
  591.         public void InitializeApplication()
  592.         {
  593.             int y = 10;
  594.             // Initialize the HUD
  595.             Button fullScreen = hud.AddButton(ToggleFullscreen,"Toggle full screen", 35, y, 125,22);
  596.             Button toggleRef = hud.AddButton(ToggleReference,"Toggle reference (F3)", 35, y += 24, 125,22);
  597.             Button changeDevice = hud.AddButton(ChangeDevice,"Change Device (F2)", 35, y += 24, 125,22);
  598.             // Hook the button events for when these items are clicked
  599.             fullScreen.Click += new EventHandler(OnFullscreenClicked);
  600.             toggleRef.Click += new EventHandler(OnRefClicked);
  601.             changeDevice.Click += new EventHandler(OnChangeDevicClicked);
  602.         }
  603.  
  604.         /// <summary>Called when the change device button is clicked</summary>
  605.         private void OnChangeDevicClicked(object sender, EventArgs e)
  606.         {
  607.             sampleFramework.ShowSettingsDialog(!sampleFramework.IsD3DSettingsDialogShowing);
  608.         }
  609.  
  610.         /// <summary>Called when the full screen button is clicked</summary>
  611.         private void OnFullscreenClicked(object sender, EventArgs e)
  612.         {
  613.             sampleFramework.ToggleFullscreen();
  614.         }
  615.  
  616.         /// <summary>Called when the ref button is clicked</summary>
  617.         private void OnRefClicked(object sender, EventArgs e)
  618.         {
  619.             sampleFramework.ToggleReference();
  620.         }
  621.  
  622.         /// <summary>
  623.         /// Entry point to the program. Initializes everything and goes into a message processing 
  624.         /// loop. Idle time is used to render the scene.
  625.         /// </summary>
  626.         static int Main() 
  627.         {
  628.             using(Framework sampleFramework = new Framework())
  629.             {
  630.                 SimpleAnimation sample = new SimpleAnimation(sampleFramework);
  631.                 // Set the callback functions. These functions allow the sample framework to notify
  632.                 // the application about device changes, user input, and windows messages.  The 
  633.                 // callbacks are optional so you need only set callbacks for events you're interested 
  634.                 // in. However, if you don't handle the device reset/lost callbacks then the sample 
  635.                 // framework won't be able to reset your device since the application must first 
  636.                 // release all device resources before resetting.  Likewise, if you don't handle the 
  637.                 // device created/destroyed callbacks then the sample framework won't be able to 
  638.                 // recreate your device resources.
  639.                 sampleFramework.Disposing += new EventHandler(sample.OnDestroyDevice);
  640.                 sampleFramework.DeviceLost += new EventHandler(sample.OnLostDevice);
  641.                 sampleFramework.DeviceCreated += new DeviceEventHandler(sample.OnCreateDevice);
  642.                 sampleFramework.DeviceReset += new DeviceEventHandler(sample.OnResetDevice);
  643.  
  644.                 sampleFramework.SetKeyboardCallback(new KeyboardCallback(sample.OnKeyEvent));
  645.                 sampleFramework.SetWndProcCallback(new WndProcCallback(sample.OnMsgProc));
  646.  
  647.                 sampleFramework.SetCallbackInterface(sample);
  648.                 try
  649.                 {
  650.  
  651.                     // Show the cursor and clip it when in full screen
  652.                     sampleFramework.SetCursorSettings(true, true);
  653.  
  654.                     // Initialize
  655.                     sample.InitializeApplication();
  656.  
  657.                     // Initialize the sample framework and create the desired window and Direct3D 
  658.                     // device for the application. Calling each of these functions is optional, but they
  659.                     // allow you to set several options which control the behavior of the sampleFramework.
  660.                     sampleFramework.Initialize( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
  661.                     sampleFramework.CreateWindow("SimpleAnimation");
  662.                     sampleFramework.CreateDevice( 0, true, Framework.DefaultSizeWidth, Framework.DefaultSizeHeight, 
  663.                         sample);
  664.  
  665.                     // Pass control to the sample framework for handling the message pump and 
  666.                     // dispatching render calls. The sample framework will call your FrameMove 
  667.                     // and FrameRender callback when there is idle time between handling window messages.
  668.                     sampleFramework.MainLoop();
  669.  
  670.                 }
  671. #if(DEBUG)
  672.                 catch (Exception e)
  673.                 {
  674.                     // In debug mode show this error (maybe - depending on settings)
  675.                     sampleFramework.DisplayErrorMessage(e);
  676. #else
  677.             catch
  678.             {
  679.                 // In release mode fail silently
  680. #endif
  681.                     // Ignore any exceptions here, they would have been handled by other areas
  682.                     return (sampleFramework.ExitCode == 0) ? 1 : sampleFramework.ExitCode; // Return an error code here
  683.                 }
  684.  
  685.                 // Perform any application-level cleanup here. Direct3D device resources are released within the
  686.                 // appropriate callback functions and therefore don't require any cleanup code here.
  687.                 return sampleFramework.ExitCode;
  688.             }
  689.         }
  690.     }
  691.  
  692.     #region Derived Frame Class
  693.     /// <summary>
  694.     /// The frame that will hold mesh animation 
  695.     /// </summary>
  696.     public class AnimationFrame : Frame
  697.     {
  698.         // Store the combined transformation matrix
  699.         private Matrix combined = Matrix.Identity;
  700.         /// <summary>The combined transformation matrix</summary>
  701.         public Matrix CombinedTransformationMatrix
  702.         {
  703.             get { return combined; } set { combined = value; }
  704.         }
  705.     }
  706.     #endregion
  707.     #region Derived Mesh Container
  708.     /// <summary>
  709.     /// The mesh container class that will hold the animation data
  710.     /// </summary>
  711.     public class AnimationMeshContainer : MeshContainer
  712.     {
  713.         // Array data
  714.         private Texture[] meshTextures = null;
  715.         private BoneCombination[] bones;
  716.         private Matrix[] offsetMatrices;
  717.         private AnimationFrame[] frameMatrices;
  718.  
  719.         // Instance data
  720.         private int numAttributes = 0;
  721.         private int numInfluences = 0;
  722.         private int numPalette = 0;
  723.  
  724.         // Public properties
  725.  
  726.         /// <summary>Retrieve the textures used for this container</summary>
  727.         public Texture[] GetTextures() { return meshTextures; }
  728.         /// <summary>Set the textures used for this container</summary>
  729.         public void SetTextures(Texture[] textures) { meshTextures = textures; }
  730.         
  731.         /// <summary>Retrieve the bone combinations used for this container</summary>
  732.         public BoneCombination[] GetBones() { return bones; }
  733.         /// <summary>Set the bone combinations used for this container</summary>
  734.         public void SetBones(BoneCombination[] b) { bones = b; }
  735.         
  736.         /// <summary>Retrieve the animation frames used for this container</summary>
  737.         public AnimationFrame[] GetFrames() { return frameMatrices; }
  738.         /// <summary>Set the animation frames used for this container</summary>
  739.         public void SetFrames(AnimationFrame[] frames) { frameMatrices = frames; }
  740.         
  741.         /// <summary>Retrieve the offset matrices used for this container</summary>
  742.         public Matrix[] GetOffsetMatrices() { return offsetMatrices; }
  743.         /// <summary>Set the offset matrices used for this container</summary>
  744.         public void SetOffsetMatrices(Matrix[] matrices) { offsetMatrices = matrices; }
  745.         
  746.         /// <summary>Total number of attributes this mesh container contains</summary>
  747.         public int NumberAttributes { get { return numAttributes; } set { numAttributes = value; } }
  748.         /// <summary>Total number of influences this mesh container contains</summary>
  749.         public int NumberInfluences { get { return numInfluences; } set { numInfluences = value; } }
  750.         /// <summary>Total number of palette entries this mesh container contains</summary>
  751.         public int NumberPaletteEntries { get { return numPalette; } set { numPalette = value; } }
  752.     }
  753.     #endregion
  754.  
  755.     #region Animation Allocation Hierarchy
  756.     /// <summary>
  757.     /// AllocateHierarchy derived class
  758.     /// </summary>
  759.     public class AnimationAllocation : AllocateHierarchy
  760.     {
  761.         SimpleAnimation parent = null;
  762.         /// <summary>Create new instance of this class</summary>
  763.         public AnimationAllocation(SimpleAnimation p) { parent = p; }
  764.  
  765.         /// <summary>Create a new frame</summary>
  766.         public override Frame CreateFrame(string name)
  767.         {
  768.             AnimationFrame frame = new AnimationFrame();
  769.             frame.Name = name;
  770.             frame.TransformationMatrix = Matrix.Identity;
  771.             frame.CombinedTransformationMatrix = Matrix.Identity;
  772.  
  773.             return frame;
  774.         }
  775.  
  776.         /// <summary>Create a new mesh container</summary>
  777.         public override MeshContainer CreateMeshContainer(string name, 
  778.             MeshData meshData, ExtendedMaterial[] materials, 
  779.             EffectInstance[] effectInstances, GraphicsStream adjacency, 
  780.             SkinInformation skinInfo)
  781.         {
  782.             // We only handle meshes here
  783.             if (meshData.Mesh == null)
  784.                 throw new ArgumentException();
  785.  
  786.             // We must have a vertex format mesh
  787.             if (meshData.Mesh.VertexFormat == VertexFormats.None)
  788.                 throw new ArgumentException();
  789.  
  790.             AnimationMeshContainer mesh = new AnimationMeshContainer();
  791.  
  792.             mesh.Name = name;
  793.             int numFaces = meshData.Mesh.NumberFaces;
  794.             Device dev = meshData.Mesh.Device;
  795.             
  796.             // Make sure there are normals
  797.             if ((meshData.Mesh.VertexFormat & VertexFormats.Normal) == 0)
  798.             {
  799.                 // Clone the mesh
  800.                 Mesh tempMesh = meshData.Mesh.Clone(meshData.Mesh.Options.Value, 
  801.                     meshData.Mesh.VertexFormat | VertexFormats.Normal, dev);
  802.  
  803.                 // Destroy current mesh, use the new one
  804.                 meshData.Mesh.Dispose();
  805.                 meshData.Mesh = tempMesh;
  806.                 meshData.Mesh.ComputeNormals();
  807.             }
  808.  
  809.             // Store the materials
  810.             mesh.SetMaterials(materials);
  811.             mesh.SetAdjacency(adjacency);
  812.             Texture[] meshTextures = new Texture[materials.Length];
  813.             
  814.             // Create any textures
  815.             for (int i = 0; i < materials.Length; i++)
  816.             {
  817.                 if (materials[i].TextureFilename != null)
  818.                 {
  819.                     meshTextures[i] = ResourceCache.GetGlobalInstance().CreateTextureFromFile(
  820.                         dev, materials[i].TextureFilename);
  821.                 }
  822.             }
  823.             mesh.SetTextures(meshTextures);
  824.             mesh.MeshData = meshData;
  825.  
  826.             // If there is skinning info, save any required data
  827.             if (skinInfo != null)
  828.             {
  829.                 mesh.SkinInformation = skinInfo;
  830.                 int numBones = skinInfo.NumberBones;
  831.                 Matrix[] offsetMatrices = new Matrix[numBones];
  832.  
  833.                 for (int i = 0; i < numBones; i++)
  834.                     offsetMatrices[i] = skinInfo.GetBoneOffsetMatrix(i);
  835.  
  836.                 mesh.SetOffsetMatrices(offsetMatrices);
  837.  
  838.                 parent.GenerateSkinnedMesh(mesh);
  839.             }
  840.  
  841.             return mesh;
  842.         }
  843.  
  844.     }
  845.     #endregion
  846. }
  847.